package com.liu.helloworldsecurity.uitls;

/** *@Author liuShanYang * @Date 2025 06 13 20 12 **/
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SignatureException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Component
public class JwtTokenUtil {

    // 从配置文件注入（推荐在application.yml中配置）
    @Value("${jwt.secret:Lsyz8ZR5E6fA2w9Y1xQ3vB7uC4mKpL7nJ9oI0iU1hG5fD3vF6gH7jK8lM9nB0vC1xX2zZ3!}")
    private String secret;

    @Value("${jwt.expiration:86400000}") // 默认24小时
    private long expirationMs;

    // 使用更安全的密钥生成方式
    private SecretKey getSigningKey() {
        return Keys.hmacShaKeyFor(secret.getBytes());
    }

    /**
     * 生成JWT令牌（包含用户名和角色）
     */
    public String generateToken(Authentication authentication) {
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + expirationMs);

        // 获取用户角色
        List<String> roles = authentication.getAuthorities().stream()
                .map(GrantedAuthority::getAuthority)
                .collect(Collectors.toList());

        return Jwts.builder()
                .setSubject(authentication.getName()) // 用户名
                .claim("roles", roles) // 自定义声明：角色列表
                .setIssuedAt(now) // 签发时间
                .setExpiration(expiryDate) // 过期时间
                .signWith(getSigningKey(), SignatureAlgorithm.HS512) // 使用HS512算法
                .compact();
    }

    /**
     * 从令牌中提取用户名
     */
    public String getUsernameFromToken(String token) {
        return Jwts.parserBuilder()
                .setSigningKey(getSigningKey())
                .build()
                .parseClaimsJws(token)
                .getBody()
                .getSubject();
    }

    /**
     * 验证令牌有效性（细化错误类型）
     */
    public boolean validateToken(String token) {
        try {
            Jwts.parserBuilder()
                    .setSigningKey(getSigningKey())
                    .build()
                    .parseClaimsJws(token);
            return true;
        } catch (ExpiredJwtException ex) {
            throw new JwtException("令牌已过期", ex);
        } catch (UnsupportedJwtException ex) {
            throw new JwtException("不支持的令牌格式", ex);
        } catch (MalformedJwtException ex) {
            throw new JwtException("令牌结构异常", ex);
        } catch (SignatureException ex) {
            throw new JwtException("签名验证失败", ex);
        } catch (IllegalArgumentException ex) {
            throw new JwtException("非法令牌参数", ex);
        }
    }

    /**
     * 获取令牌剩余有效期（毫秒）
     */
    public long getRemainingExpiration(String token) {
        Claims claims = Jwts.parserBuilder()
                .setSigningKey(getSigningKey())
                .build()
                .parseClaimsJws(token)
                .getBody();
        return claims.getExpiration().getTime() - System.currentTimeMillis();
    }
}